/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.services.reports;

import com.google.inject.Inject;
import org.xptracker.domain.Domain;
import org.xptracker.domain.Size;
import org.xptracker.domain.StoryState;

import java.util.Date;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

public class StoryHistory<T> {
  @SuppressWarnings({"UnusedDeclaration"})
  @Inject
  private Domain domain;

  private StateRetriever<T> retriever;
  private String storyId;
  private SortedMap<Date, T> timeline;
  private List<StoryState> storyStates;
  public static final StateRetriever<Double> ESTIMATES = new StateRetriever<Double>() {
    public Double retrieveValue(StoryState state) {
      return state.getEstimate();
    }
  };

  public static final StateRetriever<Size> SIZES = new StateRetriever<Size>() {
    public Size retrieveValue(StoryState state) {
      return state.getSize();
    }
  };
  
  public static final StateRetriever<Long> EFFORT = new StateRetriever<Long>() {
    public Long retrieveValue(StoryState state) {
      return state.getTotalEffort();
    }
  };

  public SortedMap<Date, T> getTimeline() {
    if (timeline == null) {
      timeline = constructTimeline();
    }
    return timeline;
  }

  private SortedMap<Date, T> constructTimeline() {
    SortedMap<Date, T> timeline = new TreeMap<Date, T>();
    for(StoryState change: getStoryStates()) {
      timeline.put(change.getStartDate(), retriever.retrieveValue(change));
    }
    return timeline;
  }

  public SortedMap<Date, T> getTimeline(Date startDate, Date endDate) {
    SortedMap<Date, T> fullTimeline = constructTimeline();
    SortedMap<Date, T> limitedTimeline = fullTimeline.subMap(startDate, new Date(endDate.getTime() + 1));
    if (!limitedTimeline.containsKey(startDate)) {
      SortedMap<Date, T> headOfTimeline = fullTimeline.headMap(startDate);
      if (!headOfTimeline.isEmpty()) {
        limitedTimeline.put(startDate, headOfTimeline.get(headOfTimeline.lastKey()));
      }
    }
    return limitedTimeline;
  }

  public List<StoryState> getStoryStates() {
    if (storyStates == null) {
      storyStates = domain.listStoryStates(storyId);
    }
    return storyStates;
  }

  public void setStoryId(String storyId) {
    this.storyId = storyId;
    storyStates = null;
  }

  public void setRetriever(StateRetriever<T> retriever) {
    this.retriever = retriever;
  }

  public static interface StateRetriever<T> {
    T retrieveValue(StoryState state);
  }
}
